//
//  main.cpp
//  FileROperation
//
//  Created by huge on 2021/8/10.
//  Copyright © 2021 huge. All rights reserved.
//

/**
 https://blog.csdn.net/tjcwt2011/article/details/81125912
 
 "r"：只能从文件中读数据，该文件必须先存在，否则打开失败
 "w"：只能向文件写数据，若指定的文件不存在则创建它，如果存在则先删除它再重建一个新文件
 "a"：向文件增加新数据(不删除原有数据)，若文件不存在则打开失败，打开时位置指针移到文件末尾
 "r+"：可读/写数据，该文件必须先存在，否则打开失败
 "w+"：可读/写数据，用该模式打开新建一个文件，先向该文件写数据，然后可读取该文件中的数据
 打开二进制文件的模式与打开文本文件的含义是一样的，不同的是模式名称里面多一个字母'b’，以表示以二进制形式打开文件。

 **/

#include <iostream>

//实例4. fprintf和fscanf函数的使用

void fprint_fscanf(){
    FILE* fp = NULL;
    fp = fopen("info.txt","w+");
    int num = 0;
    char name[10] = "leeming";
    char gender = 'M';
    
    if (fp == NULL) {
        printf("fail to open file!\n");
    }else{
        printf("opened file successful!\n");
//        fprintf(fp, "%d %s %c",num,name,gender);
        
        fputs("Builtful day!", fp);
//        fseek(fp,0L,SEEK_SET);
       
        //rewind函数的作用是使位置指针重返回文件的开头，属于文件的定位。
        rewind(fp);
        int tNum = -1;
        char tName[10] = {};
        char tName2[10] = {};
        char tGender;
        int sinf = fscanf(fp, "%s %s",tName,tName2);
        if (sinf != EOF) {
//            printf("result: %d \n",tNum);
            printf("result: %s \n",tName);
            printf("result: %s \n",tName2);

        }
    }

    
    fclose(fp);
}

/**
    3. 二进制文件操作
    3.1 数据块存取函数
 
 当要求一次存取一组数据（如，一个数组、一个结构体变量的值），fread和fwrite函数可以解决该类问题。它们的调用形式一般为：
 fread(buffer, size, count, fp);
 fwrite(buffer, size, count, fp);
 buffer：对于fread来说，指的是读入数据的存放地址；对于fwrite来说，是要输出数据的地址。
 size：读写数据时，每笔数据的大小
 count：读写数据的笔数
 fp：文件指针
**/

#define SIZE 3
typedef enum
{
    MM,
    GG
} Gender;

typedef struct
{
    char name[10];
    int age;
    Gender gender;
} Person;

void write2file(Person emp[SIZE]){
    printf("write2file!\n");
    FILE* fp = NULL;
    fp = fopen("emp2.txt", "wb");
    
    if (fp == NULL) {
        printf("fail to open file!\n");
        return;
    }else{
        for (int i=0;i<SIZE; i++) {
            if (fwrite(&emp[i], sizeof(Person), 1,fp) != 1) {
                printf("write file erro!\n");
            }
        }
    }
    
    fclose(fp);
}

void ReadFromFile(FILE* fp){
    printf("ReadFromFile!\n");
    
    fp = fopen("emp2.txt", "rb");
    if (fp == NULL) {
        return;
    }

    Person emp[SIZE];
    for (int i=0; i<SIZE; i++) {
        size_t n = fread(&emp[i], sizeof(Person), 1, fp);
        printf("n: %d\n",(int)n);
        if (n != 1 ) {
            if (
                !feof(fp)) {
                fclose(fp);
                return;
            }
        }
        printf("%-5s %4d %5d\n",emp[i].name,emp[i].age,emp[i].gender);
    }
}

/**
 3.2 随机存取函数fseek()
 函数原型：
 
 _CRTIMP int __cdecl fseek(FILE *, long, int);
 
 对流式文件可以进行顺序读写，也可以进行随机读写。关键在于控制文件的位置指针，如果位置指针是按字节位置顺序移动的，就是顺序读写。如果能将位置指针按需要移动到任意位置，就可以实现随机读写。所谓随机读写，是指读完上一个字符(字节)后，并不一定要读写其后续的字符(字节)，而可以读写文件中任意位置上所需要的字符(字节)。该函数的调用形式为：
 
 fseek(fp, offset, start);
 
 start：起始点。用0、1、2代替。0代表文件开始，名字为SEEK_SET，1代表当前位置，名字为SEEK_CUR，2代表文件末尾，名字为SEEK_END。
 
 fseek()函数一般用于二进制文件，因为文本文件要发生字符转换，计算位置时往往会发生混乱。
 
 调用实例如：
 
 fseek(fp, i*sizeof(Person), 0);

 **/

void testFseek(FILE* fp){
    fp = fopen("emp2.txt", "rb");

    Person testP;
    Person testArray[4] = {0};
    if (fp == NULL) {
        printf("fali to open file!\n");
    }else{
//        fseek(fp, -3*sizeof(Person), SEEK_END);
//        fread(&testP, sizeof(Person), 1, fp);
        fread(testArray, sizeof(Person), 4, fp);
        for (int i=0; i<4; i++) {
            printf("array: %s,%d,%d ",testArray[i].name,testArray[i].age,testArray[i].gender);
        }
//        fread(&testP, sizeof(Person), 1, fp);
//        printf("person: %s,%d,%d ",testP->name,testP->age,testP->gender);
//        printf("person: %s,%d,%d ",testP.name,testP.age,testP.gender);
    }
//    delete testP;
//    testP = NULL;
//
    fclose(fp);
}


void testWriteFlieSize(){
    FILE* fp = NULL;
    int* data = new int[1024*1024*1024];
    int* mallocData = (int*)malloc(1024*1024*1024);
//    Person p[1024000];

    fp = fopen("emp.bin", "wr");

    if (fp == NULL) {
        perror("fail to open file!\n");
        return;
    }else{
        fread(mallocData, 1024*1024*1024, 1, fp);
        for (int i=0; i<100000000; i++) {

//            fread(data, 102400, 1, fp);
//            Person* p = new Person();
            int* p = (int*)malloc(1024*1024*1024);
            printf(" addr: %d \n  size():%d \r\n",p, malloc_usable_size(p));

//            free(p);
//            int* p = new int[1024*1024*1024];

//            fwrite(p, sizeof(int), 1, fp);
//            delete p;
        }
    }
    
    fclose(fp);
}




int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, files!\n";
    
//    //例1. 打开文件并进行判断和关闭文件
//
//    FILE *fp = NULL;
//    fp = fopen("test.txt", "r");
//    if (fp == NULL) {
//
//        printf("fail to open the file!\n");
//    }else{
//        printf("The file is opened successful!\n");
//
//        while (!feof(fp)) {
//            printf("%c \n",fgetc(fp));
//        }
//        fclose(fp);
//    }
//
    
//    char filename[20], ch;
//    FILE *fp;
//    printf("Enter a filename!\n");
//    scanf("%s",filename);
//    printf("Enter some characters to output to file.");
//
//    fp = fopen("test.txt", "w");
//    if(fp != NULL)
//    {
//        ch = fgetc(fp);
//        while((ch = getchar()) != '\015')
//        {
//
//            fputc(ch, fp);
//        }
//        fclose(fp);
//
//    }
//    else
//        printf("fail to open! \n");
//    fclose(fp);
    
//    fprint_fscanf();
//    Person emp[SIZE] = {0};
//    FILE *fp = NULL;
//    write2file(emp);
//    testFseek(fp);
    
    Person* p = new Person();
    delete  p;
    testWriteFlieSize();
//
    return 0;
}
